<template>
  <canvas ref="canvas"></canvas>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'

const canvas = ref(null)
const particlesArray = ref([])
const mouse = {
  x: null,
  y: null,
  radius: 70
}

const loadSVG = async (url) => {
  const response = await fetch(url)
  const text = await response.text()
  const parser = new DOMParser()
  const xmlDoc = parser.parseFromString(text, 'image/svg+xml')
  const paths = xmlDoc.getElementsByTagName('path')
  return Array.from(paths).map((path) => path.getAttribute('d'))
}

const getParticlePositionsFromPathData = (pathData) => {
  const positions = []
  const ctx = canvas.value.getContext('2d')
  const path = new Path2D(pathData)
  const canvasWidth = canvas.value.width
  const canvasHeight = canvas.value.height

  for (let y = 0; y < canvasHeight; y += 1.4) {
    for (let x = 0; x < canvasWidth; x += 1.4) {
      if (ctx.isPointInPath(path, x, y)) {
        positions.push({ x, y })
      }
    }
  }
  return positions
}

const init = async () => {
  const ctx = canvas.value.getContext('2d')
  canvas.value.width = window.innerWidth
  canvas.value.height = window.innerHeight

  particlesArray.value = []
  const svgPaths = await loadSVG(
    'https://api.nineai.chat/files/images/riot-nine-1724381621046-nine-ac4f182b5.svg'
  )

  svgPaths.forEach((pathData) => {
    const positions = getParticlePositionsFromPathData(pathData)
    positions.forEach((pos) => {
      particlesArray.value.push(new Particle(pos.x, pos.y))
    })
  })
}

const animate = () => {
  const ctx = canvas.value.getContext('2d')
  ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
  particlesArray.value.forEach((particle) => {
    particle.draw(ctx)
    particle.update(mouse)
  })
  requestAnimationFrame(animate)
}

const handleResize = () => {
  canvas.value.width = window.innerWidth
  canvas.value.height = window.innerHeight
  init()
}

const handleMouseMove = (event) => {
  mouse.x = event.x
  mouse.y = event.y
}

onMounted(() => {
  window.addEventListener('mousemove', handleMouseMove)
  window.addEventListener('resize', handleResize)
  init()
  animate()
})

onBeforeUnmount(() => {
  window.removeEventListener('mousemove', handleMouseMove)
  window.removeEventListener('resize', handleResize)
})

// 粒子类
class Particle {
  constructor(x, y) {
    this.x = Math.random() * window.innerWidth
    this.y = Math.random() * window.innerHeight
    this.size = 1
    this.color = '#EB0029'
    this.baseX = x
    this.baseY = y
    this.density = Math.random() * 30 + 1
  }

  draw(ctx) {
    ctx.fillStyle = this.color
    ctx.beginPath()
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2)
    ctx.closePath()
    ctx.fill()
  }

  update(mouse) {
    const dx = mouse.x - this.x
    const dy = mouse.y - this.y
    const distance = Math.sqrt(dx * dx + dy * dy)
    const forceDirectionX = dx / distance
    const forceDirectionY = dy / distance
    const maxDistance = mouse.radius
    const force = (maxDistance - distance) / maxDistance
    const directionX = forceDirectionX * force * this.density
    const directionY = forceDirectionY * force * this.density

    if (distance < mouse.radius) {
      this.x -= directionX
      this.y -= directionY
    } else {
      if (this.x !== this.baseX) {
        const dx = this.x - this.baseX
        this.x -= dx / 10
      }
      if (this.y !== this.baseY) {
        const dy = this.y - this.baseY
        this.y -= dy / 10
      }
    }
  }
}
</script>

<style scoped>
canvas {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
}
</style>
